<?php
/*
 * Copyright (c) 2006 Byrne Reese. All rights reserved.
 * 
 * This library is free software; you can redistribute it and/or modify it 
 * under the terms of the BSD License.
 *
 * This library is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
 */

/**
 * GoogleCheckoutCart contains all of the classes and resources necessary
 * to generate a checkout button on your website for Google Checkout.
 * 
 * @package GoogleCheckoutCart
 * @author Byrne Reese <byrne@majordojo.com>
 * @copyright 2006-2008, Byrne Reese.
 */

/**
 * @ignore
 */
require_once("Util.php");

/**
 * 
 * @package GoogleCheckoutCart
 */
class CartItem {
  public $name;
  public $description;
  public $quantity;
  public $price;
  public $currency = "USD";
  private $privateData;
  function __construct($n,$d,$p,$q) {
    $this->name = $n;
    $this->description = $d;
    $this->price = $p;
    $this->quantity = $q;
    $this->privateData = array();
  }
  public function addPrivateData($k,$v) {
    $this->privateData[] = array($k,$v);
  }
  public function toXML() {
    $xml  = "      <item>\n";
    $xml .= "        <item-name>".$this->name."</item-name>\n";
    $xml .= "        <item-description>".$this->description."</item-description>\n";
    $xml .= "        <unit-price currency=\"".$this->currency."\">".$this->price."</unit-price>\n";
    $xml .= "        <quantity>".$this->quantity."</quantity>\n";
    if (count($this->privateData) > 0) {
      $xml .= "        <merchant-private-item-data>\n";
      foreach ($this->privateData as $d) {
	$xml .= "          <".$d[0].">".$d[1]."</".$d[0].">\n";
      }
      $xml .= "        </merchant-private-item-data>\n";
    }
    $xml .= "      </item>\n";
    return $xml;
  }
}

/* Abstact classes */

/**
 *
 * @package GoogleCheckoutCart
 */
abstract class CartButton {
  abstract public function toHTML($cart);
}

/**
 *
 * @package GoogleCheckoutCart
 */
abstract class ShoppingCart {
  public $items = array();
  public $continueShoppingURL;
  public $button;
  private $privateData;

  function __construct() {
    $this->privateData = array();
  }
  public function getTotal() {
    $t = 0;
    foreach ($this->items as $item) {
      $t += $item->price;
    }
    return $t;
  }
  public function addPrivateData($k,$v) {
    $this->privateData[] = array($k,$v);
  }
  public function addItem($item) {
    array_push($this->items,$item);
  }
  abstract public function toXML();
}

/* 
   Implementations of abstract classes
   This was added to support the use case where PayPal and Google might be 
   used together.
   In that use case PayPal implements the ShoppingCart and CartButton classes
   as well. 
*/

/**
 *
 * @package GoogleCheckoutCart
 */
class GoogleCartButton extends CartButton {
  function __construct($w,$h) {
    $this->width = $w;
    $this->height = $h;
  }
  public $width = 168;
  public $height = 64;
  public $style = "white";
  public $variant = "text";
  public $locale = "en_US";

  public function toHTML($cart) {
    $html  = "<form method=\"POST\" action=\"".CHECKOUT_SERVER."cws/v2/Merchant/".MERCHANT_ID."/checkout\">\n";
    $html .= "  <input type=\"hidden\" name=\"cart\" value=\"".base64_encode($cart->toXML())."\" />\n";
    $html .= "  <input type=\"hidden\" name=\"signature\" value=\"".base64_encode($cart->sign())."\" />\n";
    $html .= "  <input type=\"image\" name=\"Checkout\" alt=\"Checkout\" src=\"".$this->srcTag()."\" height=\"".$this->height."\" width=\"".$this->width."\" />\n";
    $html .= "</form>\n";
    return $html;
  }

  //https://sandbox.google.com/buttons/checkout.gif?merchant_id=219237163500700&w=168&h=44&style=white&variant=text&loc=en_US
  //https://sandbox.google.com/checkout/buttons/checkout.gif?merchant_id=219237163500700&w=180&h=46&style=white&variant=text&loc=en_US
  protected function srcTag() {
    return
      CHECKOUT_SERVER . 
      "buttons/checkout.gif" .
      "?merchant_id=" . MERCHANT_ID .
      "&w=" . $this->width .
      "&h=" . $this->height .
      "&style=" . $this->style .
      "&variant=" . $this->variant .
      "&loc=" . $this->locale;
  }
}

/**
 *
 * @package GoogleCheckoutCart
 */
class SmallGoogleCartButton extends GoogleCartButton {
  function __construct() {
    parent::__construct(160,43);
  }
}

/**
 *
 * @package GoogleCheckoutCart
 */
class MediumGoogleCartButton extends GoogleCartButton {
  function __construct() {
    parent::__construct(168,44);
  }
}

/**
 *
 * @package GoogleCheckoutCart
 */
class LargeGoogleCartButton extends GoogleCartButton {
  function __construct() {
    parent::__construct(180,46);
  }
}

/**
 *
 * @package GoogleCheckoutCart
 */
class GoogleShoppingCart extends ShoppingCart {
  function __construct() {
    parent::__construct();    
    $this->button =  new MediumGoogleCartButton();
  }
  public $acceptDiscounts = false;
  public $acceptGiftCertificates = false;
  public $callbackURL;

  public function sign() {
    return CalcHmacSha1(MERCHANT_KEY, $this->toXML());
  }

  public function toXML() {
    $xml = "<?".'xml version="1.0" encoding="UTF-8"'."?>\n";
    $xml .= '<checkout-shopping-cart xmlns="http://checkout.google.com/schema/2">'."\n";
    $xml .= "  <shopping-cart>\n";
    if (count($this->privateData) > 0) {
      $xml .= "        <merchant-private-data>\n";
      foreach ($this->privateData as $d) {
	$xml .= "          <".$d[0].">".$d[1]."</".$d[0].">\n";
      }
      $xml .= "        </merchant-private-data>\n";
    }
    $xml .= "    <items>\n";
    foreach ($this->items as $item) {
      $xml .= $item->toXML();
    }
    $xml .= "    </items>\n";
    $xml .= "  </shopping-cart>\n";
    $xml .= "  <checkout-flow-support>\n";
    if ($this->acceptDiscounts || $this->acceptGiftCertificates ||
	$this->continueShoppingURL) {
      $xml .= "    <merchant-checkout-flow-support>\n";
      if ($this->continueShoppingURL) {  
        $xml .= "      <continue-shopping-url>".$this->continueShoppingURL."</continue-shopping-url>\n";
      }
      if ($this->acceptDiscounts || $this->acceptGiftCertificates) {
        $xml .= "      <merchant-calculations>\n";
        $xml .= "        <merchant-calculations-url>\n";
	$xml .= "          ".$this->callbackURL."\n";
	$xml .= "        </merchant-calculations-url>\n";
	if ($this->acceptDiscounts) {  
	  $xml .= "        <accept-merchant-coupons>true</accept-merchant-coupons>\n";
	}
	if ($this->acceptGiftCertificates) {  
	  $xml .= "        <accept-gift-certificates>true</accept-gift-certificates>\n";
	}
	$xml .= "      </merchant-calculations>\n";
      }
      $xml .= "    </merchant-checkout-flow-support>\n";
    } else {
      $xml .= "    <merchant-checkout-flow-support />\n";
    }
    $xml .= "  </checkout-flow-support>\n";
    $xml .= "</checkout-shopping-cart>\n";
    return $xml;
  }
  public function validate() {
    $xml_parser = xml_parser_create();
    if (!xml_parse($xml_parser, $this->toXML(), 1)) {
      return sprintf("XML error: %s at line %d",
		     xml_error_string(xml_get_error_code($xml_parser)),
		     xml_get_current_line_number($xml_parser));
    }
    xml_parser_free($xml_parser);
    return '';
  }
}
?>
